import { STORAGE_KEY } from "@/store";
import {
	reactive,
	ref,
	computed,
	watch,
	onUnmounted,
	SetupContext,
	Ref,
} from "@vue/composition-api";
import { getCurrentConfig, getTableData } from "./hooks";
import { Stream } from "filexon";
import { ajaxDownloadFile } from "./axios";
import { warn } from "./helper";

export function useTable(ctx: SetupContext) {
	const page = ref(1);
	const isSearch = ref(false);
	const pageDivide = ref(10);

	const tableDisplayFlexList = ref(["表格固宽盒内显示", "表格全宽屏内显示"]);
	const tableDisplayFlex = computed({
		get: () => {
			const flex: boolean = ctx.root.$store.state.globalConfig.tableFullWidth;

			return flex
				? tableDisplayFlexList.value[1]
				: tableDisplayFlexList.value[0];
		},
		set: (val) => {
			if (val === tableDisplayFlexList.value[0]) {
				ctx.root.$store.commit("setTableFullWidth", false);
				window.localStorage.setItem(STORAGE_KEY.TABLE_FULLWIDTH, "0");
			} else if (val === tableDisplayFlexList.value[1]) {
				ctx.root.$store.commit("setTableFullWidth", true);
				window.localStorage.setItem(STORAGE_KEY.TABLE_FULLWIDTH, "1");
			}

			return val;
		},
	});
	const tableFlexBindClass = computed(() => {
		for (let i = 0; i < tableDisplayFlexList.value.length; i++) {
			if (tableDisplayFlexList.value[i] === tableDisplayFlex.value) {
				return i;
			}
		}

		return 0;
	});

	const downloadOps: Ref<string[]> = ref([
		"下载源文件",
		"下载当前展示数据（无缩进）",
		"下载当前展示数据（有缩进）",
		"下载当前所有数据（无缩进）",
		"下载当前所有数据（有缩进）",
		"",
	]);
	const downloadOp = ref(downloadOps.value[0]);
	const pageCount = computed(() =>
		Math.ceil(pageData.value.length / pageDivide.value) > 0 &&
		pageDivide.value > 0
			? Math.ceil(pageData.value.length / pageDivide.value)
			: 1
	);

	const pageDivideList = computed(() => {
		const list = [];

		if (tableData.value.length > 10) {
			list.push(5);
		}

		if (tableData.value.length > 20) {
			list.push(10);
		}

		if (tableData.value.length > 50) {
			list.push(20);
		}

		if (tableData.value.length > 100) {
			list.push(50);
		}

		if (tableData.value.length > 200) {
			list.push(100);
		}

		if (tableData.value.length > 400) {
			list.push(200);
		}

		if (tableData.value.length > 800) {
			list.push(400);
		}

		list.push(tableData.value.length);

		return list;
	});

	const sortTemp = reactive({
		name: "",
		order: "asc",
	});

	const { currentConfig } = getCurrentConfig(ctx);
	const { columns, tableData, labelList, searchMode } = getTableData(ctx);

	const currentData = computed(() =>
		pageData.value.slice(
			page.value * pageDivide.value - pageDivide.value,
			page.value * pageDivide.value
		)
	);
	const pageData = computed({
		get: () => {
			let result = tableData.value;

			for (let item of searchMode.value) {
				if (
					item.mode === null ||
					typeof item.val === "undefined" ||
					item.val.length === 0
				) {
					continue;
				}

				result = item.equal
					? result.filter(
							(val) => String(val[item.name]).trim() === String(item.val)
					  )
					: result.filter((val) =>
							String(val[item.name]).trim().includes(String(item.val))
					  );
			}

			return result;
		},
		set: (val) => val,
	});

	const watchPage = watch([() => page.value], () => {
		currentConfig.value.onChangePage(page.value);
	});

	const watchPageCount = watch([() => pageCount.value], () => {
		page.value = 1;
	});

	currentConfig.value.onLoadData(pageData.value);

	onUnmounted(() => {
		watchPage();
		watchPageCount();
	});

	function sortData(params: { name: string; order: "asc" | "desc" }) {
		const { name, order } = params;

		function innerCompare(a: string, b: string) {
			const search = searchMode.value.find((e) => e.name === name);
			const callback = currentConfig.value.onSortData(
				name,
				order === "asc" ? 1 : -1
			);

			if (typeof callback === "function") {
				const res = callback(a, b);
				if (typeof res === "number") {
					return res;
				} else {
					warn(
						`Invalid return type of hook function 'onSortData', it should be a 'number' type, found as '${typeof res}'`,
						"ON_SORTDATA::BAD_RET"
					);
				}
			}

			if (search !== undefined && Array.isArray(search.mode)) {
				const find = (key: string) =>
					(search.mode as any[]).find((e) => e.val.toString() === String(key));

				const p1 = find(a) ? find(a).weight : Number(a);

				const p2 = find(b) ? find(b).weight : Number(b);

				return p1 - p2;
			}

			return isNaN(Number(a)) ? a.length - b.length : Number(a) - Number(b);
		}

		pageData.value = pageData.value.sort(
			(a: any, b: any) =>
				(order === "asc" ? 1 : -1) * innerCompare(a[name], b[name])
		);
	}

	function resetSearchMode() {
		searchMode.value.forEach((item) => {
			item.val = "";
		});
		page.value = 1;
		pageDivide.value = 10;
	}

	function downloadFile() {
		const stream = new Stream();
		const injectJson = currentConfig.value.injectJson(currentConfig.value);

		let wipe = (data: any) => ({
			...injectJson,
			name: currentConfig.value.title,
			count: data.length,
			data,
		});

		const prettyJson = (data: any, flag = false) =>
			flag ? JSON.stringify(wipe(data), null, 2) : JSON.stringify(wipe(data));

		if (downloadOp.value === downloadOps.value[0]) {
			ajaxDownloadFile(currentConfig.value.data);
		} else if (downloadOp.value === downloadOps.value[1]) {
			stream.write(prettyJson(currentData.value));
			stream.out(
				currentConfig.value.title + `-第${page.value}页（无缩进）.json`
			);
		} else if (downloadOp.value === downloadOps.value[2]) {
			stream.write(prettyJson(currentData.value, true));
			stream.out(
				currentConfig.value.title + `-第${page.value}页（有缩进）.json`
			);
		} else if (downloadOp.value === downloadOps.value[3]) {
			stream.write(prettyJson(pageData.value));
			stream.out(currentConfig.value.title + "-所有数据（无缩进）.json");
		} else if (downloadOp.value === downloadOps.value[4]) {
			stream.write(prettyJson(pageData.value, true));
			stream.out(currentConfig.value.title + "-所有数据（有缩进）.json");
		}
	}

	document.title =
		ctx.root.$store.state.globalConfig.title +
		" | " +
		currentConfig.value.title;

	return {
		page,
		pageData,
		pageCount,
		isSearch,
		columns,
		pageDivide,
		pageDivideList,
		sortData,
		labelList,
		sortTemp,
		searchMode,
		currentConfig,
		resetSearchMode,
		tableDisplayFlex,
		tableDisplayFlexList,
		tableFlexBindClass,
		downloadFile,
		downloadOps,
		downloadOp,
		tableData,
	};
}
